package controller

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"

	"GoTime/models" // 请替换为实际的models包路径
	"GoTime/utils"  // 请替换为实际的utils包路径
	"github.com/gin-gonic/gin"
)

// generatePDF 是处理生成PDF文件的主要函数
func generatePDF(c *gin.Context) {
	// 从请求表单中获取school_id并转换为整数
	schoolId, _ := strconv.Atoi(c.PostForm("school_id"))
	// 从请求表单中获取province
	province := c.PostForm("province")
	// 从请求表单中获取institution_code
	institutionCode := c.PostForm("institution_code")
	// 从请求表单中获取subject
	subject := c.PostForm("subject")
	// 从请求表单中获取student_id并转换为整数
	studentId, _ := strconv.Atoi(c.PostForm("student_id"))
	// 从请求表单中获取city
	city := c.PostForm("city")

	// 根据student_id获取学员信息
	_, student, err := new(models.Student).GetStudentById(strconv.Itoa(studentId))
	if err != nil {
		// 如果获取学员信息失败，返回错误信息
		Resp(c, http.StatusCreated, err.Error(), nil)
		return
	}

	// 获取学员的学习记录
	list, err := getLearnRecords(c, studentId, subject, student.OperationStatus, city)
	if err != nil {
		// 如果获取学习记录失败，返回错误信息
		Resp(c, http.StatusCreated, err.Error(), nil)
		return
	}

	// 根据school_id和province获取考核员信息
	exam, err := new(models.Examiner).GetById(schoolId, province)
	if exam.Id == 0 {
		// 如果未找到考核员，返回错误信息
		Resp(c, http.StatusCreated, "未找到考核员", nil)
		return
	}

	// 计算学习记录的相关统计数据
	stats := calculateStats(list, province, student.OperationStatus, city)
	// 检查学员是否满足学时和里程要求
	if !student.Istransfer && !satisfyRequirements(stats, province, student.TrainingCarType, subject) {
		return
	}

	// 准备PDF文件的数据
	pdfData := preparePDFData(student, exam, stats, province, city, institutionCode)
	// 获取印章数据
	seal := getSeal(c, student, province)
	// 获取PDF文件的URL
	pdfURL := getPDFURL(subject, schoolId, studentId, pdfData)

	// 创建PDF文件
	outPDF, err := createPDF(pdfURL, pdfData, seal)
	if err != nil {
		// 如果创建PDF文件失败，返回错误信息
		Resp(c, http.StatusCreated, err.Error(), nil)
		return
	}

	// 准备签名数据
	signData, err := json.Marshal(prepareSignData(stats, student.InstitutionCode, stats.mileage))
	if err != nil {
		// 如果签名数据序列化失败，返回错误信息
		Resp(c, http.StatusCreated, err.Error(), nil)
		return
	}

	// 返回成功响应，包含生成的PDF文件和签名数据
	Resp(c, http.StatusOK, "success", map[string]interface{}{
		"ids":      stats.ids,
		"outpdf":   outPDF,
		"signdata": signData,
	})
}

// getLearnRecords 根据条件获取学员的学习记录
func getLearnRecords(c *gin.Context, studentId int, subject, operationStatus, city string) ([]*models.SubjectLearn, error) {
	// 如果学员状态为"11"或"12"，或者城市为"370800"，则获取学员的所有学习记录
	if operationStatus == "11" || operationStatus == "12" || city == "370800" {
		return new(models.LearnRecord).GetStudentAllLearnRecord(studentId)
	}
	// 否则，根据科目获取学员的学习记录
	return new(models.LearnRecord).GetSubjectLearnRecord(studentId, subject)
}

// calculateStats 计算学习记录的相关统计数据
func calculateStats(list []*models.SubjectLearn, province, operationStatus, city string) struct {
	sumTime        int
	dayRecord      map[string]int
	recArray       []map[string]string
	classRoom      map[string]int
	simulatorCount int
	classRoomCount int
	duration       int
	ids            []int
	subject1Time   int
	subject2Time   int
	subject4Time   int
	mileage        float64
} {
	// 初始化统计数据结构
	stats := struct {
		sumTime        int
		dayRecord      map[string]int
		recArray       []map[string]string
		classRoom      map[string]int
		simulatorCount int
		classRoomCount int
		duration       int
		ids            []int
		subject1Time   int
		subject2Time   int
		subject4Time   int
		mileage        float64
	}{
		dayRecord: make(map[string]int),
		recArray:  make([]map[string]string, 0),
		classRoom: make(map[string]int),
	}

	// 遍历学习记录并计算相关数据
	for _, v := range list {
		if v.Subject == subject || subject == "99" {
			stats.sumTime += v.LastingMinute
			dayString := v.StartTime.Format("2006-01-02")
			stats.dayRecord[dayString] += v.LastingMinute
			// 根据省份和地区限制每日学时
			if (province == "610000" || province == "120000") && stats.dayRecord[dayString] >= 360 {
				stats.dayRecord[dayString] = 360
			} else if stats.dayRecord[dayString] >= 240 {
				stats.dayRecord[dayString] = 240
			}
			// 如果记录未被上报，则增加未上报的学时
			if v.Isreport == "0" {
				stats.duration += v.LastingMinute
			}
			// 根据科目分类学时
			switch v.Subject {
			case "1":
				stats.subject1Time += v.LastingMinute
			case "2":
				stats.subject2Time += v.LastingMinute
			case "4":
				stats.subject4Time += v.LastingMinute
			}
			stats.ids = append(stats.ids, v.Id)
			// 根据科目和类型分类记录
			if v.Subject == "1" || v.Subject == "4" {
				if v.Type == "2" {
					stats.classRoom[dayString] += v.LastingMinute
					if stats.classRoom[dayString] > 180 {
						stats.classRoom[dayString] = 180
					}
				}
				stats.recArray = append(stats.recArray, map[string]string{"rnum": v.Sn})
			} else if province == "130000" && city == "130100" && v.Type == "3" {
				stats.simulatorCount += v.LastingMinute
				if stats.simulatorCount > 180 {
					stats.simulatorCount = 180
				}
				if operationStatus == "11" || operationStatus == "12" {
					stats.recArray = append(stats.recArray, map[string]string{"rnum": institutionCode + "9" + utils.Substr(v.Sn, -3, 4)})
				}
			} else if province == "610000" && v.Type == "3" {
				stats.simulatorCount += v.LastingMinute
			}
			stats.mileage += v.Mileage
		}
	}

	// 计算总的课堂学时
	for _, v := range stats.classRoom {
		stats.classRoomCount += v
	}

	return stats
}

// satisfyRequirements 检查学员是否满足学时和里程要求
func satisfyRequirements(stats struct {
	sumTime        int
	dayRecord      map[string]int
	recArray       []map[string]string
	classRoom      map[string]int
	simulatorCount int
	classRoomCount int
	duration       int
	ids            []int
	subject1Time   int
	subject2Time   int
	subject4Time   int
	mileage        float64
}, province, trainingCarType, subject string) bool {
	// 根据省份、培训车辆类型和科目获取所需的学时设置
	carRecordSetting := utils.CarRecordSetting(province, trainingCarType, stats.ids, subject)

	// 检查总的学时是否满足要求
	if stats.sumTime < carRecordSetting {
		Resp(c, http.StatusCreated, fmt.Sprintf("有效学时至少达到%d学时,现计时平台有效学时为：%d学时%d分",
			carRecordSetting/45, stats.sumTime/45, stats.sumTime%45), nil)
		return false
	}

	// 检查科目3的里程是否满足要求（仅在省份不是"120000"时检查）
	if subject == "3" && province != "120000" {
		if stats.mileage < 2600.0 {
			Resp(c, http.StatusCreated, fmt.Sprintf("有效里程至少达到260公里,现计时平台有效里程为：%g公里",
				stats.mileage/10), nil)
			return false
		}
	}

	// 检查省份为"610000"时，科目1和科目4的课堂学时是否满足要求
	if province == "610000" {
		if subject == "1" && stats.classRoomCount < 180 {
			Resp(c, http.StatusCreated, "科目一课堂学时必须满足180分钟", nil)
			return false
		} else if subject == "4" && stats.classRoomCount < 90 {
			Resp(c, http.StatusCreated, "科目四课堂学时必须满足90分钟", nil)
			return false
		}
	}

	return true
}

// preparePDFData 准备PDF文件的数据
func preparePDFData(data map[string]string, subject string, stats struct {
	sumTime        int
	dayRecord      map[string]int
	recArray       []map[string]string
	classRoom      map[string]int
	simulatorCount int
	classRoomCount int
	duration       int
	ids            []int
	subject1Time   int
	subject2Time   int
	subject4Time   int
	mileage        float64
}, province, city, institutionCode string) map[string]string {
	// 初始化PDF数据
	pdfData := map[string]string{
		"institution_code": institutionCode,
		"name":             data["name"],
		"sex":              data["sex"],
		"address":          data["address"],
		"idcard":           strings.Replace(data["id_number"], "t", "", -1),
		"photo":            data["image_url"],
		"phone":            data["phone"],
		"sdate":            data["sign_in_time"],
		"signature1":       "./static/admin/img/seal.png",
		"signature2":       "./static/admin/img/seal.png",
		"signature3":       "./static/admin/img/seal.png",
		"signature4":       "./static/admin/img/seal.png",
		"signyear1":        fmt.Sprintf("%s %s %s", time.Now().Format("2006"), time.Now().Format("01"), time.Now().Format("02")),
		"signyear2":        fmt.Sprintf("%s %s %s", time.Now().Format("2006"), time.Now().Format("01"), time.Now().Format("02")),
		"signyear3":        fmt.Sprintf("%s %s %s", time.Now().Format("2006"), time.Now().Format("01"), time.Now().Format("02")),
		"signyear4":        fmt.Sprintf("%s %s %s", time.Now().Format("2006"), time.Now().Format("01"), time.Now().Format("02")),
		"s1date":           fmt.Sprintf("%s %s %s", time.Now().Format("2006"), time.Now().Format("01"), time.Now().Format("02")),
		"s2date":           fmt.Sprintf("%s %s %s", time.Now().Format("2006"), time.Now().Format("01"), time.Now().Format("02")),
		"s3date":           fmt.Sprintf("%s %s %s", time.Now().Format("2006"), time.Now().Format("01"), time.Now().Format("02")),
		"s4date":           fmt.Sprintf("%s %s %s", time.Now().Format("2006"), time.Now().Format("01"), time.Now().Format("02")),
	}

	// 根据科目分类填充PDF数据
	switch subject {
	case "1":
		pdfData["s1thrhours"] = fmt.Sprintf("%d学时%d分钟", stats.sumTime/45, stats.sumTime%45)
		pdfData["s1sign"] = data["name"]
		pdfData["s1coachsign"] = data["coach_name"]
		pdfData["s1coachdate"] = fmt.Sprintf("%s %s %s", time.Now().Format("2006"), time.Now().Format("01"), time.Now().Format("02"))
		pdfData[data["training_car_type"]] = "https://oss.hahajishi.cn/static/duigou.jpg"
		pdfData["subject"] = "1"
	case "2":
		pdfData["s2thrhours"] = fmt.Sprintf("%d学时%d分钟", stats.sumTime/45, stats.sumTime%45)
		pdfData["s2sign"] = data["name"]
		pdfData["s2coachsign"] = data["coach_name"]
		pdfData["s2coachdate"] = fmt.Sprintf("%s %s %s", time.Now().Format("2006"), time.Now().Format("01"), time.Now().Format("02"))
		pdfData["subject"] = "2"
	case "3":
		pdfData["s3thrhours"] = fmt.Sprintf("%d学时%d分钟", stats.sumTime/45, stats.sumTime%45)
		pdfData["s3sign"] = data["name"]
		pdfData["s3coachsign"] = data["coach_name"]
		pdfData["s3coachdate"] = fmt.Sprintf("%s %s %s", time.Now().Format("2006"), time.Now().Format("01"), time.Now().Format("02"))
		pdfData["subject"] = "3"
	case "4":
		pdfData["s4thrhours"] = fmt.Sprintf("%d学时%d分钟", stats.sumTime/45, stats.sumTime%45)
		pdfData["s4sign"] = data["name"]
		pdfData["s4coachsign"] = data["coach_name"]
		pdfData["s4coachdate"] = fmt.Sprintf("%s %s %s", time.Now().Format("2006"), time.Now().Format("01"), time.Now().Format("02"))
		pdfData["subject"] = "4"
	}

	// 如果地址为空，设置为" "
	if pdfData["address"] == "" {
		pdfData["address"] = " "
	}

	return pdfData
}

// getSeal 获取印章数据
func getSeal(c *gin.Context, Zhangurl string, province string) string {
	if province == "340000" || province == "370000" || province == "610000" || province == "120000" {
		if Zhangurl == "" {
			Resp(c, http.StatusCreated, "请将驾校图片章发给我们客服人员", nil)
			return ""
		}
		newZhang := Zhangurl
		if strings.Contains(newZhang, "chrono") {
			s := strings.Split(newZhang, "sign")
			newZhang = "http://oss.hahajishi.cn/sign" + s[1]
		}
		resp, err := http.Get(newZhang)
		if err != nil {
			Resp(c, http.StatusCreated, err.Error(), nil)
			return ""
		}
		defer resp.Body.Close()
		zhangdata, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			Resp(c, http.StatusCreated, err.Error(), nil)
			return ""
		}
		sa := make([]string, 0)
		for _, v := range zhangdata {
			sa = append(sa, fmt.Sprintf("%02X", v))
		}
		return strings.Join(sa, "")
	}
	return c.PostForm("seal")
}

// getPDFURL 获取PDF文件的URL
func getPDFURL(subject string, schoolId int, studentId int, pdfData map[string]string) string {
	if subject == "1" {
		return "http://oss.hahajishi.cn/graduation/new_stage.pdf"
	}

	// 获取学员上一个审核通过的科目PDF文件URL
	recordFile, err := new(models.Reported).GetLastPdfFile(schoolId, studentId)
	if err != nil {
		Resp(c, http.StatusCreated, err.Error(), nil)
		return ""
	}

	if recordFile.FileUrl != "" {
		return recordFile.FileUrl
	}

	// 如果未找到上一个审核通过的科目PDF文件URL，则使用默认的PDF文件URL
	pdfData[student.TrainingCarType] = "https://oss.hahajishi.cn/static/duigou.jpg"
	pdfData["stunum"] = pdfData["institution_code"]
	return "http://oss.hahajishi.cn/graduation/new_stage.pdf"
}

// createPDF 创建PDF文件
func createPDF(pdfURL string, pdfData map[string]string, seal string) (string, error) {
	if seal != "" {
		return utils.CreateNewPdf(pdfURL, pdfData, "r", seal)
	}
	return utils.CreatePdf(pdfURL, pdfData, "r", seal)
}

// prepareSignData 准备签名数据
func prepareSignData(stats struct {
	sumTime        int
	dayRecord      map[string]int
	recArray       []map[string]string
	classRoom      map[string]int
	simulatorCount int
	classRoomCount int
	duration       int
	ids            []int
	subject1Time   int
	subject2Time   int
	subject4Time   int
	mileage        float64
}, institutionCode string, mileage float64) map[string]interface{} {
	return map[string]interface{}{
		"inscode":       institutionCode,
		"stunum":        institutionCode,
		"subject":       stats.recArray[len(stats.recArray)-1]["subject"],
		"totaltime":     stats.sumTime, // 培训部分总学时
		"vehicletime":   0,
		"classtime":     0,
		"simulatortime": 0,
		"networktime":   0,
		"duration":      stats.duration, // 培训学时
		"examresult":    1,              // 考核结果
		"mileage":       fmt.Sprintf("%.2f", mileage/10),
		"rectype":       5,
		"recarray":      stats.recArray,
	}
}

// Resp 处理HTTP响应并返回JSON格式的数据
func Resp(c *gin.Context, statusCode int, message string, data interface{}) {
	c.JSON(statusCode, gin.H{
		"message": message,
		"data":    data,
	})
}
